import itertools, os, re
import pyrem_strs.utility.powergraph as powergraph
import pyrem_strs.originedstr as rm

# python-graph (http://code.google.com/p/python-graph/) ver. 1.6.3
from pygraph.classes.digraph import digraph as pg_digraph 
from pygraph.readwrite.dot import write as pg_write

# read source files from current directory
fileTable = rm.FileTable()
fileTable.read_from_directory("", re.compile(".+[.](h(xx|pp)?|hh)$"), recursive=True)
#fileTable.read_from_directory("", re.compile(".+[.]([ch](xx|pp)?|cc|hh)$"), recursive=True)

# find identifiers
s = r'[uU]?"(\\.|[^"])*"'
pat = re.compile("|".join([
        r"\b(friend|typedef)\s+(class|struct|enum)\s+(?P<useid>[a-zA-Z_]\w*(::[a-zA-Z_]\w*)*)", # using identifier
        r"\b(?P<def>(class|struct|enum)\s+)?(?P<id>[a-zA-Z_]\w*(::[a-zA-Z_]\w*)*)", # identifier
        s, s.replace('"', "'"), # string literals
        r"//[^\n]*\n", r'/[*]([*]+[^/]|.)[*]+/'])) # comments
referredIds, definedIds = [], []
for _, ns in sorted(fileTable.iteritems()):
    for m in pat.finditer(rm.origined_str(ns)):
        id = m.group('id')
        if not id: id = m.group('useid')
        if m.group('def'): definedIds.append(id)
        elif id: referredIds.append(id)
referredIds = filter(set(definedIds).__contains__, referredIds)

# build graph of dependency (by name) between the source files
graph = pg_digraph()

filesInGraph = set()
def add_file_to_graph(f):
    if not graph.has_node(f): graph.add_node(f)
    filesInGraph.add(f)

for defName, defs in itertools.groupby(sorted(definedIds)):
    defFiles = [id.origin0.namedstr for id in defs]
    refFiles = [id.origin0.namedstr for id in referredIds if id == defName]
    if not set(refFiles) - set(defFiles): continue # skip if the id is used only in one file
    if not defFiles: continue
    for df in defFiles:
        add_file_to_graph(df.name)
        for rf in refFiles:
            add_file_to_graph(rf.name)
            edge = (rf.name, df.name)
            if not graph.has_edge(edge): graph.add_edge(edge)

powerEdges, powerNodes = powergraph.calc_power_digraph(graph.edges())

powerGraph = pg_digraph()
def to_power_label(names): return "\\n".join(n.replace(os.path.sep, "/") for n in names)
for pn in powerNodes: powerGraph.add_node(to_power_label(pn), attrs=[ ( "shape", "box" ) ])
for pe in powerEdges: powerGraph.add_edge((to_power_label(pe[0]), to_power_label(pe[1])))

file("powergraph.dot", "w").write(pg_write(powerGraph))
